﻿using NopSolutions.NopCommerce.BusinessLogic;
using NopSolutions.NopCommerce.BusinessLogic.Events;
using NopSolutions.NopCommerce.BusinessLogic.Model;
using NopSolutions.NopCommerce.BusinessLogic.Utils;
using NopSolutions.NopCommerce.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace NopSolutions.NopCommerce.Web.Modules.Cart
{
    public partial class CheckoutOnePageRedux : BaseNopFrontendUserControl
    {
        protected ShoppingCart cart = null;
        protected bool shoppingCartRequiresShipping = false;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            Load += OnUserControlLoad;

            btnConfirm.Click += OnConfirmButtonClick;
            rblShippingAddresses.SelectedIndexChanged += OnShippingAddressesSelectedIndexChanged;
            rblShippingMethods.SelectedIndexChanged += OnShippingMethodsSelectedIndexChanged;
            rblBillingAddresses.SelectedIndexChanged += OnBillingAddressesSelectedIndexChanged;
            rblPaymentMethod.SelectedIndexChanged += OnPaymentMethodSelectedIndexChanged;
        }

        void OnUserControlLoad(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BindData();
            }
        }

        #region Properties

        /// <summary>
        /// Gets the current shopping cart
        /// </summary>
        public ShoppingCart Cart
        {
            get
            {
                if (cart == null)
                {
                    cart = ShoppingCartService.GetCurrentShoppingCart(ShoppingCartTypeEnum.ShoppingCart);
                }
                return cart;
            }
        }

        /// <summary>
        /// Gets the shipping address
        /// </summary>
        protected Address ShippingAddress
        {
            get
            {
                var address = ctrlShippingAddress.Address;
                if (address.AddressId != 0 && NopContext.Current.User != null)
                {
                    var prevAddress = CustomerService.GetAddressById(address.AddressId);
                    if (prevAddress.CustomerId != NopContext.Current.User.CustomerId)
                        return null;
                    address.CustomerId = prevAddress.CustomerId;
                    address.CreatedOn = prevAddress.CreatedOn;
                }
                else
                {
                    address.CreatedOn = DateTime.UtcNow;
                }

                return address;
            }
        }

        //protected ShippingOption SelectedShippingOption
        //{
        //    get
        //    {
        //        ShippingOption shippingOption = null;
        //        foreach (RepeaterItem item in this.rptShippingOptions.Items)
        //        {
        //            var rdShippingOption = (RadioButton)item.FindControl("rdShippingOption");
        //            var hfShippingRateComputationMethodId = (HiddenField)item.FindControl("hfShippingRateComputationMethodId");
        //            var hfName = (HiddenField)item.FindControl("hfName");

        //            if (rdShippingOption.Checked)
        //            {
        //                int shippingRateComputationMethodId = Convert.ToInt32(hfShippingRateComputationMethodId.Value);
        //                string name = hfName.Value;

        //                string error = string.Empty;
        //                var shippingOptions = this.ShippingService.GetShippingOptions(Cart, NopContext.Current.User,
        //                    NopContext.Current.User.ShippingAddress, shippingRateComputationMethodId, ref error);
        //                shippingOption = shippingOptions.Find((so) => so.Name == name);
        //                break;
        //            }
        //        }
        //        return shippingOption;
        //    }
        //    set
        //    {
        //        foreach (RepeaterItem item in this.rptShippingOptions.Items)
        //        {
        //            var rdShippingOption = (RadioButton)item.FindControl("rdShippingOption");
        //            var hfName = (HiddenField)item.FindControl("hfName");

        //            if (value == null)
        //            {
        //                rdShippingOption.Checked = false;
        //            }
        //            else
        //            {
        //                string name = hfName.Value;
        //                if (name == value.Name)
        //                {
        //                    rdShippingOption.Checked = true;
        //                    break;
        //                }
        //            }
        //        }
        //    }
        //}

        #endregion

        #region Methods

        protected void BindData()
        {
            shoppingCartRequiresShipping = ShippingService.ShoppingCartRequiresShipping(Cart);

            pnlShipping.Visible = false;
            if (shoppingCartRequiresShipping)
            {
                pnlShipping.Visible = true;

                BindShippingAddresses();
                BindShippingMethods();
            }

            BindBillingAddresses();
            BindPaymentMethods();
        }

        #region Shipping Address

        protected void BindShippingAddresses()
        {
            rblShippingAddresses.Items.Clear();

            var shippingAddresses = GetAllowedShippingAddresses(NopContext.Current.User);
            if (shippingAddresses.Any())
            {
                shippingAddresses.ForEach(p => rblShippingAddresses.Items.Add(new ListItem(BuildAddressName(p), p.AddressId.ToString())));

                rblShippingAddresses.Items.Add(new ListItem(GetLocaleResourceString("Checkout.OrEnterNewAddress"), "0"));
                ctrlShippingAddress.Visible = false;
            }
            else
            {
                rblShippingAddresses.Items.Add(new ListItem(GetLocaleResourceString("Checkout.EnterShippingAddress"), "0"));
                ctrlShippingAddress.Visible = true;
            }

            rblShippingAddresses.SelectedIndex = 0;
        }

        protected List<Address> GetAllowedShippingAddresses(Customer customer)
        {
            var addresses = new List<Address>();
            if (customer == null)
                return addresses;

            foreach (var address in customer.ShippingAddresses)
            {
                var country = address.Country;
                if (country != null && country.AllowsShipping)
                {
                    addresses.Add(address);
                }
            }

            return addresses;
        }

        protected void SelectShippingAddress(Address shippingAddress)
        {
            int addressId = 0;

            if (shippingAddress == null)
            {
                // not saved address
                addressId = 0;
            }
            else if (shippingAddress.AddressId == 0)
            {
                //check if address already exists
                var shippingAddress2 = NopContext.Current.User.ShippingAddresses.FindAddress(shippingAddress.FirstName,
                    shippingAddress.LastName, shippingAddress.PhoneNumber, shippingAddress.Email,
                    shippingAddress.FaxNumber, shippingAddress.Company,
                    shippingAddress.FullAddress,
                    shippingAddress.City, shippingAddress.StateProvinceId, shippingAddress.ZipPostalCode,
                    shippingAddress.CountryId);

                if (shippingAddress2 != null)
                {
                    shippingAddress = shippingAddress2;
                }
                else
                {
                    shippingAddress.CustomerId = NopContext.Current.User.CustomerId;
                    shippingAddress.IsBillingAddress = false;
                    shippingAddress.CreatedOn = DateTime.UtcNow;
                    shippingAddress.UpdatedOn = DateTime.UtcNow;

                    CustomerService.InsertAddress(shippingAddress);
                }

                // new address
                addressId = shippingAddress.AddressId;
            }
            else
            {
                // existing address
                addressId = shippingAddress.AddressId;
            }

            NopContext.Current.User.ShippingAddressId = addressId;
            CustomerService.UpdateCustomer(NopContext.Current.User);

        }

        #endregion

        #region Shipping Methods

        protected void BindShippingMethods()
        {
            rblShippingMethods.Items.Clear();

            var errors = string.Empty;
            var address = NopContext.Current.User.ShippingAddress;
            var shippingOptions = ShippingService.GetShippingOptions(Cart, NopContext.Current.User, address, ref errors);

            if (!string.IsNullOrEmpty(errors))
            {
                LogService.InsertLog(LogTypeEnum.ShippingError, errors, errors);
                pnlShippingMethod.Visible = false;
                lShippingMethodsError.Text = Server.HtmlEncode(errors);
            }
            else
            {
                if (shippingOptions.Any())
                {
                    pnlShippingMethod.Visible = true;

                    shippingOptions.ForEach(p =>
                    {
                        var name = string.Format("{0}<br /><br />{1}", p.Name, p.Description);
                        var id = p.ShippingRateComputationMethodId.ToString();

                        var item = new ListItem(name, p.Name);
                        item.Attributes.Add("ShippingRateComputationMethodId", id);

                        rblShippingMethods.Items.Add(item);
                    });

                    rblShippingMethods.SelectedIndex = 0;

                    if (NopContext.Current.User != null &&
                        NopContext.Current.User.LastShippingOption != null)
                    {
                        //already selected shipping option
                        //SelectedShippingOption = NopContext.Current.User.LastShippingOption;
                        rblShippingMethods.SelectedValue = NopContext.Current.User.LastShippingOption.ShippingRateComputationMethodId.ToString();
                    }
                }
                else
                {
                    pnlShippingMethod.Visible = false;
                    lShippingMethodsError.Text = GetLocaleResourceString("Checkout.ShippingIsNotAllowed");
                }
            }
        }

        //protected string FormatShippingOption(ShippingOption shippingOption)
        //{
        //    //calculate discounted and taxed rate
        //    Discount appliedDiscount = null;
        //    decimal shippingTotalWithoutDiscount = shippingOption.Rate;
        //    decimal discountAmount = this.ShippingService.GetShippingDiscount(NopContext.Current.User, shippingTotalWithoutDiscount, out appliedDiscount);
        //    decimal shippingTotalWithDiscount = shippingTotalWithoutDiscount - discountAmount;

        //    if (shippingTotalWithDiscount < decimal.Zero)
        //        shippingTotalWithDiscount = decimal.Zero;

        //    shippingTotalWithDiscount = Math.Round(shippingTotalWithDiscount, 2);

        //    decimal rateBase = this.TaxService.GetShippingPrice(shippingTotalWithDiscount, NopContext.Current.User);
        //    decimal rate = this.CurrencyService.ConvertCurrency(rateBase, this.CurrencyService.PrimaryStoreCurrency, NopContext.Current.WorkingCurrency);

        //    string rateStr = PriceHelper.FormatShippingPrice(rate, true);
        //    return string.Format("({0})", rateStr);
        //}

        #endregion

        #region Billing Address

        protected void BindBillingAddresses()
        {
            rblBillingAddresses.Items.Clear();

            var billingAddresses = GetAllowedBillingAddresses(NopContext.Current.User);
            if (billingAddresses.Any())
            {
                billingAddresses.ForEach(p => rblBillingAddresses.Items.Add(new ListItem(BuildAddressName(p), p.AddressId.ToString())));
                rblBillingAddresses.Items.Add(new ListItem(GetLocaleResourceString("Checkout.OrEnterNewAddress"), "0"));
                ctrlBillingAddress.Visible = false;
            }
            else
            {
                rblBillingAddresses.Items.Add(new ListItem(GetLocaleResourceString("Checkout.EnterBillingAddress"), "0"));
                ctrlBillingAddress.Visible = true;
            }

            if (shoppingCartRequiresShipping)
            {
                rblBillingAddresses.Items.Insert(0, new ListItem(GetLocaleResourceString("Checkout.BillingAddressTheSameAsShippingAddress"), "-1"));
                ctrlBillingAddress.Visible = false;
            }

            rblBillingAddresses.SelectedIndex = 0;
        }

        protected List<Address> GetAllowedBillingAddresses(Customer customer)
        {
            var addresses = new List<Address>();
            if (customer == null)
                return addresses;

            foreach (var address in customer.BillingAddresses)
            {
                var country = address.Country;
                if (country != null && country.AllowsBilling)
                {
                    addresses.Add(address);
                }
            }

            return addresses;
        }

        private void SelectBillingAddress(Address billingAddress)
        {
            int addressId = 0;

            if (billingAddress == null)
            {
                //set default billing address
                addressId = 0;
            }
            else if (billingAddress.AddressId == 0)
            {
                //check if address already exists
                var billingAddress2 = NopContext.Current.User.BillingAddresses.FindAddress(billingAddress.FirstName,
                     billingAddress.LastName, billingAddress.PhoneNumber, billingAddress.Email,
                     billingAddress.FaxNumber, billingAddress.Company,
                     billingAddress.FullAddress,
                     billingAddress.City, billingAddress.StateProvinceId, billingAddress.ZipPostalCode,
                     billingAddress.CountryId);

                if (billingAddress2 != null)
                {
                    billingAddress = billingAddress2;
                }
                else
                {
                    billingAddress.CustomerId = NopContext.Current.User.CustomerId;
                    billingAddress.IsBillingAddress = true;
                    billingAddress.CreatedOn = DateTime.UtcNow;
                    billingAddress.UpdatedOn = DateTime.UtcNow;

                    this.CustomerService.InsertAddress(billingAddress);
                }

                addressId = billingAddress.AddressId;
            }
            else
            {
                addressId = billingAddress.AddressId;
            }

            NopContext.Current.User.BillingAddressId = addressId;
            CustomerService.UpdateCustomer(NopContext.Current.User);
        }

        #endregion

        #region Payment Methods

        protected void BindPaymentMethods()
        {
            int? filterByCountryId = null;
            if (NopContext.Current.User.BillingAddress != null &&
                NopContext.Current.User.BillingAddress.Country != null)
            {
                filterByCountryId = NopContext.Current.User.BillingAddress.CountryId;
            }

            var boundPaymentMethods = new List<PaymentMethod>();
            var paymentMethods = this.PaymentService.GetAllPaymentMethods(filterByCountryId);
            foreach (var pm in paymentMethods)
            {
                switch (pm.PaymentMethodType)
                {
                    case PaymentMethodTypeEnum.Unknown:
                    case PaymentMethodTypeEnum.Standard:
                        {
                            if (!Cart.IsRecurring ||
                                this.PaymentService.SupportRecurringPayments(pm.PaymentMethodId) != RecurringPaymentTypeEnum.NotSupported)
                                boundPaymentMethods.Add(pm);
                        }
                        break;
                    case PaymentMethodTypeEnum.Button:
                        {
                            //PayPal Express is placed here as button
                            if (pm.SystemKeyword == "PayPalExpress")
                            {
                            }
                        }
                        break;
                    default:
                        break;
                }
            }

            if (boundPaymentMethods.Any())
            {
                pnlPaymentMethod.Visible = true;
                lPaymentMethodsError.Visible = false;

                boundPaymentMethods.ForEach(p =>
                {
                    var item = new ListItem();
                    item.Text = p.VisibleName;
                    item.Value = p.PaymentMethodId.ToString();

                    rblPaymentMethod.Items.Add(item);
                });

                rblPaymentMethod.SelectedIndex = 0;
                if (NopContext.Current.User != null &&
                    NopContext.Current.User.LastPaymentMethod != null)
                {
                    //already selected payment method
                    rblPaymentMethod.SelectedValue = NopContext.Current.User.LastPaymentMethod.PaymentMethodId.ToString();
                }
            }
            else
            {
                pnlPaymentMethod.Visible = false;
                lPaymentMethodsError.Visible = true;
                lPaymentMethodsError.Text = GetLocaleResourceString("Checkout.NoPaymentMethods");
            }
        }

        #endregion

        protected string BuildAddressName(Address address)
        {
            string theAddress = string.Empty;

            if (address.CompanyLegalForm)
            {
                theAddress = Server.HtmlEncode(address.Company);

                if (!string.IsNullOrWhiteSpace(address.CompanyFiscalCode))
                {
                    theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.CompanyFiscalCode"), address.CompanyFiscalCode) + "; ");
                }
                if (!string.IsNullOrWhiteSpace(address.CompanyRegComNumber))
                {
                    theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.CompanyFiscalCode"), address.CompanyRegComNumber) + "; ");
                }
                if (!string.IsNullOrWhiteSpace(address.CompanyBank))
                {
                    theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.Company.Bank"), address.CompanyBank) + "; ");
                }
                if (!string.IsNullOrWhiteSpace(address.CompanyBankAccount))
                {
                    theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.Company.BankAccount"), address.CompanyBankAccount) + "; ");
                }
            }
            else
            {
                theAddress = Server.HtmlEncode(string.Format("{0} {1} ({2})", address.FirstName, address.LastName, address.Email));
            }

            theAddress += "<br/>";

            if (!string.IsNullOrWhiteSpace(address.FullAddress))
            {
                theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.Address1"), address.FullAddress) + "; ");
            }
            if (address.Country != null)
            {
                theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.Country"), address.Country.Name) + "; ");
            }
            if (!string.IsNullOrWhiteSpace(address.City))
            {
                theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.City"), address.City) + "; ");
            }
            if (address.StateProvince != null)
            {
                theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.StateProvince"), address.StateProvince.Name) + "; ");
            }
            if (!string.IsNullOrWhiteSpace(address.ZipPostalCode))
            {
                theAddress += Server.HtmlEncode(string.Format("{0} {1}", GetLocaleResourceString("Address.ZipPostalCode"), address.ZipPostalCode) + "; ");
            }

            return theAddress;
        }

        #endregion

        #region Events

        void OnConfirmButtonClick(object sender, EventArgs e)
        {
            Page.Validate("Checkout");
            if (Page.IsValid)
            {
                PaymentInfo paymentInfo = new PaymentInfo();
                paymentInfo.CustomerLanguage = NopContext.Current.WorkingLanguage;
                paymentInfo.CustomerCurrency = NopContext.Current.WorkingCurrency;

                shoppingCartRequiresShipping = ShippingService.ShoppingCartRequiresShipping(Cart);

                // shipping
                if (shoppingCartRequiresShipping)
                {
                    Address shippingAddress = null;

                    // shipping address
                    if (rblShippingAddresses.SelectedValue == "0")
                    {
                        // new address
                        shippingAddress = ctrlShippingAddress.Address;
                        shippingAddress.CreatedOn = DateTime.UtcNow;
                    }
                    else
                    {
                        var addressId = Convert.ToInt32(rblShippingAddresses.SelectedValue);

                        shippingAddress = CustomerService.GetAddressById(addressId);
                        if (shippingAddress != null && NopContext.Current.User != null)
                        {
                            var prevAddress = CustomerService.GetAddressById(shippingAddress.AddressId);
                            if (prevAddress.CustomerId != NopContext.Current.User.CustomerId)
                                return;
                        }
                    }

                    SelectShippingAddress(shippingAddress);
                    paymentInfo.ShippingAddress = NopContext.Current.User.ShippingAddress;

                    // shipping option
                    var selectedMethod = rblShippingMethods.SelectedItem;

                    ShippingOption shippingOption = null;

                    if (selectedMethod != null && selectedMethod.Selected)
                    {
                        var value = Convert.ToInt32(selectedMethod.Attributes["ShippingRateComputationMethodId"]);
                        var name = selectedMethod.Value;
                        var error = string.Empty;

                        var shippingOptions = ShippingService.GetShippingOptions(Cart, NopContext.Current.User, NopContext.Current.User.ShippingAddress, value, ref error);
                        shippingOption = shippingOptions.Find((so) => so.Name == name);
                    }

                    if (shippingOption != null)
                    {
                        NopContext.Current.User.LastShippingOption = shippingOption;
                    }
                }

                Address billingAddress = null;
                // billing
                if (rblBillingAddresses.SelectedValue == "-1")
                {
                    billingAddress = NopContext.Current.User.ShippingAddress;
                }
                else if (rblBillingAddresses.SelectedValue == "0")
                {
                    // new address
                    billingAddress = ctrlBillingAddress.Address;
                    billingAddress.CreatedOn = DateTime.UtcNow;
                }
                else
                {
                    var addressId = Convert.ToInt32(rblBillingAddresses.SelectedValue);
                    billingAddress = CustomerService.GetAddressById(addressId);
                }

                SelectBillingAddress(billingAddress);
                paymentInfo.BillingAddress = NopContext.Current.User.BillingAddress;

                // payment
                var selectedPayment = rblPaymentMethod.SelectedItem;
                if (selectedPayment != null && selectedPayment.Selected)
                {
                    int paymentMethodId = Convert.ToInt32(selectedPayment.Value);

                    var paymentMethod = PaymentService.GetPaymentMethodById(paymentMethodId);
                    if (paymentMethod != null && paymentMethod.IsActive)
                    {
                        //save selected payment methods
                        NopContext.Current.User.LastPaymentMethodId = paymentMethodId;
                        CustomerService.UpdateCustomer(NopContext.Current.User);
                    }
                }

                paymentInfo.PaymentMethodId = NopContext.Current.User.LastPaymentMethodId;

                int orderId = 0;
                string result = this.OrderService.PlaceOrder(paymentInfo, NopContext.Current.User, out orderId);

                var order = this.OrderService.GetOrderById(orderId);
                if (!string.IsNullOrEmpty(result))
                {
                    lConfirmOrderError.Text = Server.HtmlEncode(result);
                    return;
                }
                else
                {
                    this.PaymentService.PostProcessPayment(order);
                }

                Response.Redirect("~/checkoutcompleted.aspx");
            }
        }

        void OnShippingAddressesSelectedIndexChanged(object sender, EventArgs e)
        {
            // if new address show the address edit control
            if (rblShippingAddresses.SelectedValue == "0")
            {
                ctrlShippingAddress.Visible = true;
                //SelectShippingAddress(null);
            }
            else
            {
                ctrlShippingAddress.Visible = false;

                //var addressId = Convert.ToInt32(rblShippingAddresses.SelectedValue);

                //var shippingAddress = CustomerService.GetAddressById(addressId);
                //if (shippingAddress != null && NopContext.Current.User != null)
                //{
                //    var prevAddress = CustomerService.GetAddressById(shippingAddress.AddressId);
                //    if (prevAddress.CustomerId != NopContext.Current.User.CustomerId)
                //        return;
                //}

                //SelectShippingAddress(shippingAddress);
            }
        }

        void OnShippingMethodsSelectedIndexChanged(object sender, EventArgs e)
        {
            //var selectedMethod = rblShippingMethods.SelectedItem;

            //ShippingOption shippingOption = null;

            //if (selectedMethod != null && selectedMethod.Selected)
            //{
            //    var value = Convert.ToInt32(selectedMethod.Attributes["ShippingRateComputationMethodId"]);
            //    var name = selectedMethod.Value;
            //    var error = string.Empty;

            //    var shippingOptions = ShippingService.GetShippingOptions(Cart, NopContext.Current.User, NopContext.Current.User.ShippingAddress, value, ref error);
            //    shippingOption = shippingOptions.Find((so) => so.Name == name);
            //}

            //if (shippingOption != null)
            //{
            //    NopContext.Current.User.LastShippingOption = shippingOption;
            //}
        }

        void OnBillingAddressesSelectedIndexChanged(object sender, EventArgs e)
        {
            if (rblBillingAddresses.SelectedValue == "-1")
            {
                ctrlBillingAddress.Visible = false;
                //SelectBillingAddress(NopContext.Current.User.ShippingAddress);
            }
            else if (rblBillingAddresses.SelectedValue == "0")
            {
                ctrlBillingAddress.Visible = true;
                //SelectBillingAddress(null);
            }
            else
            {
                ctrlBillingAddress.Visible = false;

                //var addressId = Convert.ToInt32(rblBillingAddresses.SelectedValue);
                //var address = CustomerService.GetAddressById(addressId);
                //SelectBillingAddress(address);
            }
        }

        void OnPaymentMethodSelectedIndexChanged(object sender, EventArgs e)
        {
            //var selectedPayment = rblPaymentMethod.SelectedItem;
            //if (selectedPayment != null && selectedPayment.Selected)
            //{
            //    int paymentMethodId = Convert.ToInt32(selectedPayment.Value);

            //    var paymentMethod = this.PaymentService.GetPaymentMethodById(paymentMethodId);
            //    if (paymentMethod != null && paymentMethod.IsActive)
            //    {
            //        //save selected payment methods
            //        NopContext.Current.User.LastPaymentMethodId = paymentMethodId;
            //        this.CustomerService.UpdateCustomer(NopContext.Current.User);
            //    }
            //}
        }

        #endregion
    }
}